
#include "buffer.h"
#include "mylog.h"
#include "zmalloc.h"

#include <string.h>
#include <stdio.h>

static unsigned long long id = 0;
static const int kCheapPrepend = 8;

struct buffer* initBuffer(int initSize) {
	struct buffer* buf = NULL;
	buf = (struct buffer*)zcalloc(sizeof(struct buffer));
	if (!buf) {
		mylog(LOG_WARNING, "initBuffer zcalloc error!!!\n");
		return NULL;
	}

	buf->id = id++;
	buf->data = NULL;
	buf->readIndex = kCheapPrepend;
	buf->writeIndex = kCheapPrepend;
	buf->size = initSize;
	if (initSize == 0) {
		mylog(LOG_INFO, "init Buffer id[%d]", buf->id);
		return buf;
	}

	buf->data = (char* )zmalloc(kCheapPrepend + initSize);
	if (!buf->data) {
		mylog(LOG_WARNING, "initBuf zmalloc buffer data error!!!\n");
		zfree(buf);
		return NULL;
	}

	return buf;
}

void destroyBuffer(struct buffer* buf) {
	if (!buf) {
		mylog(LOG_WARNING, "destroyBuffer error!!! buf is null!!!\n");
		return;
	}

	mylog(LOG_INFO, "destroy Buffer id[%d]", buf->id);
	if (buf->data) {
		zfree(buf->data);
	}
	zfree(buf);
}

char* getWriteIndexBuffer(struct buffer* buf) {
	if (!buf) {
		return NULL;
	}

	return (char*)buf->data + buf->writeIndex;
}

char* getReadIndexBuffer(struct buffer* buf) {
	if (!buf) {
		return NULL;
	}

	return beginBuffer(buf) + buf->readIndex;
}

void moveWriteIndexBuffer(struct buffer* buf, int moveLen) {
	if (!buf) {
		return;
	}

	buf->writeIndex += moveLen;
}

void moveReadIndexBuffer(struct buffer* buf, int moveLen) {
	if (!buf) {
		return;
	}

	buf->readIndex += moveLen;
}

char* beginBuffer(struct buffer* buf) {
	if (!buf) {
		return NULL;
	}
	return (char*)buf->data;
}

void appendBuffer(struct buffer* buffer, const char* data, int dataLen) {
	if (!buffer || !data || dataLen <= 0) {
		return;
	}

	if (!buffer->data) {
		buffer->data = (char *)zmalloc(dataLen + kCheapPrepend);
		buffer->writeIndex = kCheapPrepend;
		buffer->readIndex = kCheapPrepend;
	}

	if (dataLen > getWriteableBytesBuffer(buffer)) {
		mylog(LOG_DEBUG, "zrealloc buffer data ing...\n");
		expandBuffer(buffer);
	}

	memcpy(beginBuffer(buffer) + buffer->writeIndex, data, dataLen);
	buffer->writeIndex += dataLen;
}

void prependBuffer(struct buffer* buf, const char* data, int dataLen) {
	if (!buf || !data || dataLen <= 0) {
		mylog(LOG_WARNING, "prependBuffer buf is null!!!");
		return;
	}

	if (dataLen <= prependableBytesBuffer(buf)) {
		mylog(LOG_WARNING, "buf prependableBytesBuffer error!!!");
		return;
	}

	int readIndex = buf->readIndex;
	readIndex -= dataLen;
	memcpy(beginBuffer(buf) + readIndex, data, dataLen);
}

int expandBuffer(struct buffer* buf) {
	if (!buf) {
		return -1;
	}

	int reallocSize = buf->size << 1;
	char* tmp = (char *)zrealloc(buf->data, reallocSize);
	if (!tmp) {
		mylog(LOG_WARNING, "zrealloc buffer data error, buf id[%d] realloc size[%d]!!!\n", buf->id, reallocSize);
		return -2;
	}
	buf->size = reallocSize;
	buf->data = tmp;
	return 0;
}

int getWriteableBytesBuffer(struct buffer* buf) {
	if (!buf) {
		return 0;
	}

	return buf->size - buf->writeIndex;
}

int getReadableBytesBuffer(struct buffer* buf) {
	if (!buf) {
		return 0;
	}

	return buf->writeIndex - buf->readIndex;
}

void retrieveAllBuffer(struct buffer* buf) {
	if (!buf) {
		return;
	}

	buf->writeIndex = kCheapPrepend;
	buf->readIndex = kCheapPrepend;
}

int prependableBytesBuffer(struct buffer* buf) {
	if (!buf) {
		return 0;
	}

	return buf->readIndex;
}

